﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint.StsAdmin;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using System.Reflection;
using System.Collections.Specialized;

namespace Macaw.Moss2007.TimerJobServerSelectorSolution
{
    public class JobServerExtension : ISPStsadmCommand
    {
        public string GetHelpMessage(string command)
        {
            return "-url <url of webapp> -job <job guid|name> -server [server name]";
        }

        public int Run(string command, StringDictionary keyValues, out string output)
        {

            command = command.ToLowerInvariant();

            switch (command)
            {
                case "jobserver":
                    if (keyValues.Count != 3)
                    {
                        output = GetHelpMessage(command);
                        return -1;
                    }
                    return this.SetJobServer(keyValues, out output);

                default:
                    throw new InvalidOperationException();
            }
        }

        private int SetJobServer(StringDictionary keyValues, out string output)
        {
            output = "Something went wrong!";

            if (!keyValues.ContainsKey("url"))
            {
                throw new InvalidOperationException("The 'url' parameter was not specified.");
            }

            String url = keyValues["url"];

            if (!keyValues.ContainsKey("job"))
            {
                throw new InvalidOperationException("The 'job' parameter was not specified.");
            }

            String job = keyValues["job"];

            if (!keyValues.ContainsKey("server"))
            {
                throw new InvalidOperationException("The 'server' parameter was not specified.");
            }

            String server = keyValues["server"];

            try
            {
                using (SPSite site = new SPSite(url))
                {
                    SPJobDefinition jobdef = null;

                    try
                    {
                        Guid jobguid = new Guid(job);
                        jobdef = site.WebApplication.JobDefinitions[jobguid];
                        if (jobdef == null) throw new Exception();
                    }
                    catch
                    {
                        try
                        {
                            foreach (SPJobDefinition jd in site.WebApplication.JobDefinitions)
                            {
                                if (jd.Name.Equals(job, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    jobdef = jd;
                                }
                            }
                            if (jobdef == null) throw new Exception();
                        }
                        catch
                        {

                            StringBuilder jobs = new StringBuilder();
                            foreach (SPJobDefinition j in site.WebApplication.JobDefinitions)
                            {
                                jobs.AppendFormat("{0}\t({1})\r\n", j.Name, j.Id);
                            }
                            output = string.Format("Unable to find job with guid or name '{0}' for WebApplication '{1}'. The following Jobs are registered for this WebApplication:'\r\n{2}", job, site.WebApplication.Name, jobs.ToString());
                            return -1;
                        }
                    }

                    if (jobdef != null)
                    {
                        SPServer spserver = null;

                        foreach (SPServer s in SPFarm.Local.Servers)
                        {
                            if (s.Name.Equals(server, StringComparison.InvariantCultureIgnoreCase))
                            {
                                spserver = s;
                            }
                        }

                        output = string.Format("Setting Job '{0}' to run on Server '{1}'", jobdef.Name, (spserver == null ? "Undefined" : spserver.Name));
                        FieldInfo CurrentJobServerFI = typeof(SPJobDefinition).GetField("m_Server", BindingFlags.NonPublic | BindingFlags.Instance);
                        if (CurrentJobServerFI == null) throw new Exception("m_Server field not found");

                        CurrentJobServerFI.SetValue(jobdef, spserver);
                        jobdef.Update();
                        return 0;
                    }

                }

                return -1;

            }

            catch (Exception ex)
            {
                output = ex.Message;
            }
            return -1;
        }
    }
}
